﻿using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Xml;
using System.Xml.Serialization;
using System.Xml.XPath;
using System.Xml.Xsl;
using Quellenverwaltung.Data.Source;
using Quellenverwaltung.Data.SRU;
using Quellenverwaltung.SRU.Exceptions;

namespace Quellenverwaltung.SRU
{
    public class ServiceConsumer
    {
        public Service Service { get; set; }

        public ServiceConsumer(Service service)
        {
            Service = service;
        }

        public SRUService RequestServiceSpecification()
        {
            String xmlResult = Service.requestSpecification();
            return handleSpecification(xmlResult);
        }

        public Sources Request(CQLBuilder cqlBuilder) 
        {
            String sruXmlResult  = "";
            try
            {
               sruXmlResult = Service.request(cqlBuilder);
            }
            catch
            {
                return new Sources();
            }

                if (sruXmlResult.Contains("SRUServiceException"))
                {
                    SRUServiceException exception = handleDiagnostics(sruXmlResult);
                    if (exception != null)
                        throw exception;
                    else
                        throw new SRUServiceException();
                }
            
                if (sruXmlResult.Contains("<diagnostic xmlns=\"http://www.loc.gov/zing/srw/diagnostic/\">")) {
                    SRUServiceException exception = new SRUServiceException();
                    exception.Details = "Es ist ein Problem mit dem Transformationsdienst der \"Library of Congress\" aufgetreten.";
                    if (sruXmlResult.Contains("<message>System temporarily unavailable</message>"))
                    {
                        exception.Details = exception.Details + "Fehler: System temporär nicht verfügbar";
                    }
                    throw exception;
                }

            if (String.IsNullOrEmpty(sruXmlResult) || sruXmlResult.Contains("<zs:numberOfRecords>0</zs:numberOfRecords>")) {
                return new Sources();
            } else {
                return handleSources(sruXmlResult);
            }

        }

        private Sources handleSources(String sruXmlResult)
        {
            MemoryStream stream = transform(sruXmlResult, "Quellenverwaltung.SRU.Transformations.MOD.xsl");
            return deserialise<Sources>(stream);
        }

        private SRUServiceException handleDiagnostics(string sruXmlResult)
        {
            MemoryStream stream = transform(sruXmlResult, "Quellenverwaltung.SRU.Transformations.ServiceException.xsl");
            return deserialise<SRUServiceException>(stream);
        }

        private SRUService handleSpecification(String xmlResult)
        {
            MemoryStream stream = transform(xmlResult, "Quellenverwaltung.SRU.Transformations.ServiceDescription.xsl");
            return deserialise<SRUService>(stream);
        }

        private T deserialise<T>(Stream xml)
        {
            XmlSerializer serializer = new XmlSerializer(typeof(T));
            T response = (T)serializer.Deserialize(xml);
            return response;
        }

        private MemoryStream transform(String xmlResult, String xsltFile)
        {
 
            XPathDocument xPathDoc = new XPathDocument(new StringReader(xmlResult));
            XslCompiledTransform transform = new XslCompiledTransform(true);
            //transform.Load(xsltFile);
            XmlReader xsltReader = XmlReader.Create(this.GetType().Assembly.GetManifestResourceStream(xsltFile));

            transform.Load(xsltReader);

            MemoryStream stream = new MemoryStream();
            XmlWriter writer = new XmlTextWriter(stream, Encoding.UTF8);

            transform.Transform(xPathDoc, null, writer);
            stream.Position = 0;

            return stream;
        }
    }
}
